#!/usr/bin/env python
#
# GAE-Appengine-CMS
# Copyright (c) 2010 ITBelt (itbelt.com)
# Licensed under the GPL license:
# http://www.gnu.org/licenses/gpl.html
#

import os

try:
  from django import v0_96
except ImportError:
  pass 

import django
import django.conf
try:
  directory = os.path.join(os.path.dirname(__file__),'templates')
  django.conf.settings.configure(
    TEMPLATE_LOADERS=(
      'django.template.loaders.filesystem.load_template_source',
      'templateloader.load_template_source',
    ),
    TEMPLATE_DIRS=(directory,),
  )
except (EnvironmentError, RuntimeError):
  pass
import random
import string
import sys
import wsgiref.handlers
import datetime
import re
from django.utils import simplejson
from google.appengine.ext.webapp import util


from google.appengine.api import users
from google.appengine.api import mail
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.api import memcache

from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import login_required

import django.template
import django.template.loader

import models
#import templateloader

_DEBUG = True

template.register_template_library('templatefilters')

def set_trace():
    import pdb, sys
    debugger = pdb.Pdb(stdin=sys.__stdin__,
        stdout=sys.__stdout__)
    debugger.set_trace(sys._getframe().f_back)

def getFullPath(template_name):
    directory = os.path.dirname(__file__)
    path = os.path.join(directory, os.path.join('templates', template_name))
    return path
            
def exists(template_name):
    path = getFullPath(template_name)
    return os.path.exists(path)

def renderTemplate(template_name, values):
    path = getFullPath(template_name)
    return template.render(path, values, debug=_DEBUG)

def render(template_text, values):
    t=template.Template(template_text)
    c=template.Context(values)
    return t.render(c)

def import_model(class_name): 
    mod = __import__('models', globals(), locals(), [class_name])
    return getattr(mod, class_name)

class BasePageHandler(webapp.RequestHandler):
    """Supplies a common template generation function.

    When you call generate(), we augment the template variables supplied with
    the current user in the 'user' variable and the current webapp request
    in the 'request' variable.
    """
    terminated=False
    page_template = None
    
    def checkRequest(self, *args):
        if not self.path:
            path = self.request.path
            path = path[1:]
            if path == '':
                path = 'default.html'
            self.path=path.lower()        
        
        if not exists(self.path):
            self.page_template = models.PageTemplate.getByUrl(self.path)
            if not self.page_template:
                return False
        
        return True
        
    def onPreInit(self, *args):
        self.path = None
    
    def init(self, *args):
        #os.environ.handler=self
        os.environ['handler']=self
        self.values = {
            'request': self.request,
            'user': users.GetCurrentUser(),
            'login_url': users.CreateLoginURL(self.request.uri),
            'logout_url': users.CreateLogoutURL('http://' + self.request.host + '/'),
            'application_name': 'GAE-CMS',
        }     
    def onInit(self, *args):
        pass
    def onLoad(self, *args):
        pass
    def onPreRender(self, *args):
        pass
    def generate(self, *args):
        if self.page_template:
            t, origin = django.template.loader.find_template_source(self.page_template.name)
            self.response.out.write(django.template.Template(t,origin,self.page_template.name).render(django.template.Context(self.values)))
        else:
            self.response.out.write(renderTemplate(self.path, self.values))
            
    def unload(self, *args):
        pass
    
    def end(self, code=None):
        if code:
            self.error(code)
        self.terminate()
        
    def terminate(self):
        self.terminated=True;
        return
    
    def get(self, *args):
        self.onPreInit(*args)
        
        if self.terminated: return
        if not self.checkRequest(*args):
            self.error(404)
            return
        
        self.init(*args)        
        self.onInit(*args)
        if self.terminated: return
        self.onLoad(*args)
        if self.terminated: return
        
        self.processGet(*args)
        if self.terminated: return

        self.onPreRender(*args)
        if self.terminated: return
               
        self.generate(*args)
        self.unload(*args)
    
    def processPost(self, *args):
        pass
    def processGet(self, *args):
        pass
        
    def post(self, *args):
        self.onPreInit(*args)
        if self.terminated: return
        if not self.checkRequest(*args):
            self.error(404)
            return
        
        self.init(*args)
        self.onInit(*args)
        if self.terminated: return
        self.onLoad(*args)
        if self.terminated: return
        
        self.processPost(*args)
        if self.terminated: return
        
        self.onPreRender(*args)
        if self.terminated: return
        self.generate(*args)
        self.unload(*args)

      
class MainPage(BasePageHandler):    
  def onPreInit(self,*args):
      self.path=None
      
class MainEntityPage(BasePageHandler):    
  def onPreInit(self,*args):
      self.path=args[0]
      self.args=args
      
class AdminPage(BasePageHandler):
    """Admin pages"""
    def onPreInit(self,*args):
        if not users.get_current_user():
            self.redirect(users.CreateLoginURL(self.request.uri), True)
            self.end() 
            return
        if not args[0]:
            path='default.html'
        elif args[1]:
            path='entity.html'
        else:
            path='entity_list.html'
              
        self.path='admin/'+path

class AdminEntityPage(AdminPage):
    def get_entity_class(self, name):
        cn=name.lower()
        d=[m for m in dir(models) if m.lower()== cn]
        if len(d)<1:
            self.end(403) 
            return None
        return d[0]
    
    def processGet(self,*args):
        if args[0]:
            class_name=self.get_entity_class(args[0])
            if not class_name: return
            entity_class=import_model(class_name)
        
            self.values['actionUrl'] = args[0]
            if args[1]:
                entity_form_class=import_model(class_name+'Form')
                
                if args[1]=='add':
                    self.values['form_body']=entity_form_class()
                else:
                    id=int(args[1])
                    entity = entity_class.get_by_id(id)
                    self.values['form_body']=entity_form_class(instance=entity)
                    self.values['id_field']=id
            else:
                list = entity_class.all().order("-created")
                self.values['list'] = list
    
    def processPost(self,*args):
        class_name=self.get_entity_class(args[0])
        if not class_name: return
            
        if args[1]=='del' or self.request.get('btnDelete'):
            keys = self.request.get_all('entity')   
            k=[db.Key.from_path(class_name,int(key)) for key in keys]
            db.delete(k)
            self.redirect('/admin/'+args[0])
            return
        
        sid=self.request.get('id_id')
        entity_form_class=import_model(class_name+'Form')
        if sid:
            id = int(sid)
            entity_class=import_model(class_name)
            item = entity_class.get_by_id(id)
            if not item:
                self.end(403)
                return
            data = entity_form_class(data=self.request.POST, instance=item)
            item.clear_cache()
        else:
            data = entity_form_class(data=self.request.POST)
            
        if data.is_valid():
          entity = data.save(commit=False)
          entity.put()
          self.redirect('/admin/entity/'+args[0])
        else:
          self.values['form_body']=data
          self.values['id_field']=sid     
    
class AdminCRUDHandler(webapp.RequestHandler):
    def get(self, *args):
        user=users.GetCurrentUser()
        if not user:
            self.end(403)
            return
        
        self._get(args[1])
        
    def post(self, *args):
        user=users.GetCurrentUser()
        if not user:
            self.end(403)
            return
        
        action=args[0]
        if action == 'upd':
            self._upd(args[1])
            self._redirect()
        elif action == 'del':
            self._del()
            self._redirect()
        else:
            self.end(403)
            
    def _del(self):
        skeys = self.request.get('keys')
        keys=skeys.split(',')
        db.delete(keys)

        
class AdminEntityCRUD(AdminCRUDHandler):
    def _redirect(self):
        self.redirect('/admin/news.html', True)
        
    def _get(self, key):
        entity = models.News.get(key)
        if not entity:
            self.end(403)
            return
        self.response.out.write(entity.toJSON())
        
    def _upd(self, key):
        title = self.request.get('title')
        body = self.request.get('description')
        
        if not title or not body:
            self.end(403)
            return
            
        if key:
            entity = models.News.get(key)
            if not entity:
                self.end(403)
                return
        else:
            entity = None

        if entity:
            entity.title = db.Text(title)
            entity.body = db.Text(body)
        else:
            entity = models.News(title=title, body=body)

        entity.put()

class ActionHandler(webapp.RequestHandler):
    def get(self, *args):
        if not users.get_current_user():
            self.redirect(users.CreateLoginURL(self.request.uri), True)
            self.end() 
            return
        
        if args[0]=='clear_cache':
            memcache.flush_all()
        
        uri=self.request.headers['Referer']
        self.redirect(uri, True)

_URLS = (
            ('/admin/action/([A-Za-z0-9_]*)',ActionHandler),
            ('/admin/entity(?:/)?([A-Za-z0-9_]*)(?:/([A-Za-z0-9\._]*))?',AdminEntityPage),
            ('/admin(?:/)?([A-Za-z0-9_]*)(?:/([A-Za-z0-9\._]*))?',AdminPage),
            ('/([A-Za-z0-9_]*)(?:/([A-Za-z0-9\._]*))?',MainEntityPage),
            ('(?:/([A-Za-z]{2}))?/(.*)', MainPage)
        )


def main(argv):
  application = webapp.WSGIApplication(_URLS, debug=_DEBUG)
  wsgiref.handlers.CGIHandler().run(application)


if __name__ == '__main__':
  main(sys.argv)
